package ledgerapi

import (

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

type StateData interface {
	Serialize() ([]byte, error)
	DataType() string
	Keys() []string
}

type StateDataDb interface {
	Add(StateData) error
	Get(dataType, key string, df DeserializeFun) (StateData, error)
	Update(StateData) error
	Del(dataType, key string) error
	SetEvent(name string, eventData string) error
}

type StateDataLedgerDb struct {
	Ctx contractapi.TransactionContextInterface
}

type DeserializeFun func(data []byte) (StateData, error)

func(db *StateDataLedgerDb) Add(stateData StateData) error {
	stub := db.Ctx.GetStub()
	key, err := stub.CreateCompositeKey(stateData.DataType(), stateData.Keys())
	if err != nil {
		return err
	}
	data, err := stateData.Serialize()
	if err != nil {
		return err
	}
	return stub.PutState(key, data)
}


func(db *StateDataLedgerDb) Get(dataType, key string, df DeserializeFun) (StateData, error) {
	stub := db.Ctx.GetStub()
	key, err := stub.CreateCompositeKey(dataType, []string{key})
	if err != nil {
		return nil, err
	}
	data, err := stub.GetState(key)
	if err != nil {
		return nil, err
	}
	sd, err := df(data)
	if err != nil {
		return nil, err
	}
	return sd, err
}


func(db *StateDataLedgerDb) Update(stateData StateData) error{
	return db.Add(stateData)
}

func(db *StateDataLedgerDb) Del(dataType, key string) error{
	stub := db.Ctx.GetStub()
	key, err := stub.CreateCompositeKey(dataType, []string{key})
	if err != nil {
		return err
	}
	return stub.DelState(key)
}

func(db *StateDataLedgerDb) SetEvent(name string, eventData string) error {
	stub := db.Ctx.GetStub()
	return stub.SetEvent(name, []byte(eventData))
}


